package com.aube.control.mediaproxy;

import android.text.TextUtils;

import com.android.volley.ServerError;
import com.aube.control.mediaproxy.NanoHTTPD.Response;
import com.aube.control.mediaproxy.NanoHTTPD.Status;
import com.huyn.baseframework.utils.Utils;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;

/**
 * NanoHTTPD代理拦截到请求后,通过此方法重新封装向目标服务器发送请求,并将输出流转接回去
 * Created by huyaonan on 16/7/21.
 */
public class NanoHttpUtil {

    private static NanoHttpUtil mInstance;
    HttpURLConnection connection;
    private boolean alive = true;
    private static String TAG = "";
    private static NanoHTTPD mNanoHttpInstance;

    public static NanoHTTPD.Response performTask(String url, String tag, HashMap<String, String> headers, NanoHTTPD nanoHTTPD) {
        if(mInstance != null) {
            mInstance.stop();
        }

        mNanoHttpInstance = nanoHTTPD;

        mInstance = new NanoHttpUtil();
        TAG = tag;
        return mInstance.performRequest(url, headers);
    }

    private void stop() {
        try {
            alive = false;
            if (connection != null)
                connection.disconnect();
//            Utils.Log(TAG, "disconnect!!!!!!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public NanoHTTPD.Response performRequest(String url, HashMap<String, String> headers) {
        URL parsedUrl = null;
        InputStream in = null;
        try {
            parsedUrl = new URL(url);

            Utils.Log(TAG, "perform proxy request:" + url);

            HttpURLConnection connection = openConnection(parsedUrl);

            if(headers != null) {
                Utils.Log(TAG, "++++++++++++++++++request header++++++++++++++++++");
                for (String headerName : headers.keySet()) {
                    Utils.Log(TAG, "header:" + headerName + ":" + headers.get(headerName));
                    connection.addRequestProperty(headerName, headers.get(headerName));
                }
                Utils.Log(TAG, "++++++++++++++++++request header++++++++++++++++++");
            }

            connection.setRequestMethod("GET");

            int responseCode = connection.getResponseCode();
            Utils.Log(TAG, "--------responsecode--------" + responseCode);
            if (responseCode == -1)
                return null;

            boolean gzip = false;
            int length=0;
            String range=null;
            String status=null;
            Utils.Log(TAG, "--------response header--------");
            for (Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
                String key = header.getKey();
                String value = header.getValue().get(0);
                Utils.Log(TAG, "header:" + key + ":" + value);
                if (key != null) {
                    if("Content-Encoding".equalsIgnoreCase(key) && value.equalsIgnoreCase("gzip"))
                        gzip = true;
                    else if("Content-Length".equalsIgnoreCase(key) && !TextUtils.isEmpty(value))
                        length = Integer.parseInt(value);
                    else if("Content-Range".equalsIgnoreCase(key) && !TextUtils.isEmpty(value))
                        range = value;
                } else {
                    status = value;
                }
            }
            Utils.Log(TAG, "--------response header--------length:" + length);

            try {
                in = connection.getInputStream();
            } catch (IOException ioe) {
                in = connection.getErrorStream();
            }
            if (gzip) {
                in = new GZIPInputStream(in);
            }
            if (in == null) {
                throw new ServerError();
            }
//            consumeData(in);
            Response response = mNanoHttpInstance.new Response(Status.OK, "video/mp4", in, length);
//            NanoHTTPD.Response response = new NanoHTTPD.Response(Status.OK, "video/mp4", in, length);
            if(!TextUtils.isEmpty(range))
                response.addHeader("Content-Range", range);
            response.setResponseStatus(status);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void testDownloadSpeed(String url) {
        URL parsedUrl = null;
        InputStream in = null;
        try {
            parsedUrl = new URL(url);

            HttpURLConnection connection = (HttpURLConnection) parsedUrl.openConnection();//openConnection(parsedUrl);

            connection.setRequestMethod("GET");

            int responseCode = connection.getResponseCode();
            if (responseCode == -1)
                return;

            boolean gzip = false;
            int length=0;
            String range=null;
            String status=null;
            Utils.Log(TAG, "--------response header--------");
            for (Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
                String key = header.getKey();
                String value = header.getValue().get(0);
                Utils.Log(TAG, "header:" + key + ":" + value);
                if (key != null) {
                    if("Content-Encoding".equalsIgnoreCase(key) && value.equalsIgnoreCase("gzip"))
                        gzip = true;
                    else if("Content-Length".equalsIgnoreCase(key) && !TextUtils.isEmpty(value))
                        length = Integer.parseInt(value);
                    else if("Content-Range".equalsIgnoreCase(key) && !TextUtils.isEmpty(value))
                        range = value;
                } else {
                    status = value;
                }
            }
            Utils.Log(TAG, "--------response header--------length:" + length);

            try {
                in = connection.getInputStream();
            } catch (IOException ioe) {
                in = connection.getErrorStream();
            }
            if (gzip) {
                in = new GZIPInputStream(in);
            }
            if (in == null) {
                throw new ServerError();
            }

            long BUFFER_SIZE = 500 * 1024;
            byte[] buff = new byte[(int) BUFFER_SIZE];
            int size = 0;
//            Utils.Log(TAG, "send data...pending:" + pending);
            while (true) {
                long bytesToRead = BUFFER_SIZE;
                int read = in.read(buff, 0, (int) bytesToRead);
                if (read <= 0) {
                    break;
                }
                size += read;
//                Utils.Log(TAG, "sended size..." + size + "/" + (size * 100f) / pending);
            }
            Utils.Log(TAG, "send data..." + size);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void consumeData(InputStream data) {
        try {
            long BUFFER_SIZE = 500 * 1024;
            byte[] buff = new byte[(int) BUFFER_SIZE];
            int size = 0;
//            Utils.Log(TAG, "send data...pending:" + pending);
            while (true) {
                long bytesToRead = BUFFER_SIZE;
                int read = data.read(buff, 0, (int) bytesToRead);
                if (read <= 0) {
                    break;
                }
                size += read;
//                Utils.Log(TAG, "sended size..." + size + "/" + (size * 100f) / pending);
            }
            Utils.Log(TAG, "send data..." + size);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private HttpURLConnection openConnection(URL url) throws IOException {
        HttpURLConnection connection = createConnection(url);

        int timeoutMs = 30000;
        connection.setConnectTimeout(timeoutMs);
        connection.setReadTimeout(timeoutMs);
        connection.setUseCaches(false);
        connection.setDoInput(true);

        return connection;
    }

    /**
     * Create an {@link HttpURLConnection} for the specified {@code url}.
     */
    protected HttpURLConnection createConnection(URL url) throws IOException {
        return (HttpURLConnection) url.openConnection();
    }

}
